package org.aplikator.client.shared.descriptor;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jboss.errai.marshalling.client.api.Marshaller;
import org.jboss.errai.marshalling.client.api.MarshallingSession;
import org.jboss.errai.marshalling.client.api.json.EJArray;
import org.jboss.errai.marshalling.client.api.json.EJBoolean;
import org.jboss.errai.marshalling.client.api.json.EJObject;
import org.jboss.errai.marshalling.client.api.json.EJValue;

//TODO: Remove
public class WidgetDTOFactory {
	
	private static WidgetDTOFactory _INSTANCE = new WidgetDTOFactory();
	private static Map<String, Command> COMMANDS = new HashMap<String, Command>();

	static {
		COMMANDS.put(ComboBoxDTO.TYPE_KEY, new ComboBoxDTOCommand());
		COMMANDS.put(LabelFieldDTO.TYPE_KEY, new ComboBoxDTOCommand());
		COMMANDS.put(BinaryFieldDTO.TYPE_KEY, new BinaryFieldDTOCommand());
		COMMANDS.put(DateFieldDTO.TYPE_KEY, new DateFieldDTOCommand());
		COMMANDS.put(PanelDTO.TYPE_KEY, new PanelDTOCommand());
		COMMANDS.put(ReferenceFieldDTO.TYPE_KEY, new ReferenceFieldDTOCommand());
		COMMANDS.put(TableDTO.TYPE_KEY, new TableDTOCommand());
		COMMANDS.put(TextAreaDTO.TYPE_KEY, new TableDTOCommand());
		COMMANDS.put(TextFieldDTO.TYPE_KEY, new TextFieldDTOCommand());
		COMMANDS.put(FunctionWidgetDTO.TYPE_KEY, new FunctionWidgetDTOCommand());
	}

	private WidgetDTOFactory() {}
		
	public static WidgetDTOFactory getInstance() {
		return _INSTANCE;
	}

	public WidgetDTO instanceWidget(EJValue ejval, MarshallingSession ctx) {
		if (ejval.isObject() != null) {
			String val = ejval.isObject().get("type").isString().stringValue();
			return COMMANDS.get(val).instantiate(ejval.isObject(), ctx);	
		} else throw new UnsupportedOperationException("unsupported json object");
	}
	
	
	public static abstract class Command {

		public abstract WidgetDTO instantiate(EJObject ejObj, MarshallingSession ctx);
		
		void initDefaultProps(EJObject ejObj, WidgetDTO w) {
			if (ejObj.containsKey("size") && (ejObj.get("size").isNumber() != null)) {
				w.setSize(ejObj.get("size").isNumber().intValue());
			}
			if (ejObj.containsKey("formatPattern") && (ejObj.get("formatPattern").isString() != null)) {
				w.setFormatPattern(ejObj.get("formatPattern").isString().stringValue());
			} 
			if (ejObj.containsKey("enabled") && (ejObj.get("enabled").isBoolean() != null)) {
				w.setEnabled(ejObj.get("enabled").isBoolean().booleanValue());
			}			
		}
	}

	
	
	public static class ComboBoxDTOCommand extends Command {
		@Override
		public WidgetDTO instantiate(EJObject ejObj, MarshallingSession ctx) {
			ComboBoxDTO cb = new ComboBoxDTO();
			super.initDefaultProps(ejObj, cb);
			return cb;
		}
	}

	public static class LabelFieldDTOCommand extends Command {
		@Override
		public WidgetDTO instantiate(EJObject ejObj, MarshallingSession ctx) {
			LabelFieldDTO lb = new LabelFieldDTO();
			super.initDefaultProps(ejObj, lb);
			return lb;
		}
	}

	public static class BinaryFieldDTOCommand extends Command {

		@Override
		public WidgetDTO instantiate(EJObject ejObj, MarshallingSession ctx) {
			BinaryFieldDTO bfieldDto = new BinaryFieldDTO();
			super.initDefaultProps(ejObj, bfieldDto);
			if (ejObj.containsKey("entityId")) {
				bfieldDto.setEntityId(ejObj.get("entityId").isString().stringValue());
			}

			return bfieldDto;
		}
		
	}

	public static class DateFieldDTOCommand extends Command {

		@Override
		public WidgetDTO instantiate(EJObject ejObj, MarshallingSession ctx) {
			DateFieldDTO dfield = new DateFieldDTO();
			super.initDefaultProps(ejObj, dfield);
			return dfield;
		}
		
	}
	public static class PanelDTOCommand extends Command {

		@Override
		public WidgetDTO instantiate(EJObject ejObj, MarshallingSession ctx) {
			PanelDTO pdto = new PanelDTO();
			super.initDefaultProps(ejObj, pdto);
			if (ejObj.containsKey("frame")) {
				pdto.setFrame(ejObj.get("frame").isBoolean().booleanValue());
			}
			if (ejObj.containsKey("horizontal")) {
				pdto.setHorizontal(ejObj.get("horizontal").isBoolean().booleanValue());
			}
			if (ejObj.containsKey("children")) {
				EJArray array = ejObj.get("children").isArray();
				if (array != null) {
					List<WidgetDTO> list = new ArrayList<WidgetDTO>();
					for (int i = 0, ll= array.size(); i < ll; i++) {
						EJValue ejValue = array.get(i);
						if (ejValue.isObject() != null) {
							list.add(WidgetDTOFactory.getInstance().instanceWidget(ejValue, ctx));
						}
					}
					pdto.setChildren(list);
				}
			}
			return pdto;
		}
		
	}
	
	public static class ReferenceFieldDTOCommand extends Command {

		@Override
		public WidgetDTO instantiate(EJObject ejObj, MarshallingSession ctx) {
			ReferenceFieldDTO refDTO = new ReferenceFieldDTO();
			super.initDefaultProps(ejObj, refDTO);
			if (ejObj.containsKey("view")) {
				EJValue viewChild = ejObj.get("view");
				Marshaller<Object> marshaller = ctx.getMarshallerInstance(ViewDTO.class.getName());
				Object dView = marshaller.demarshall(viewChild, ctx);
				refDTO.setView((ViewDTO) dView);
			}

			if (ejObj.containsKey("child")) {
				EJValue widgetChild = ejObj.get("child");
				WidgetDTO childWidget = WidgetDTOFactory.getInstance().instanceWidget(widgetChild, ctx);
				refDTO.setChild(childWidget);
			}
			
			return refDTO;
		}
		
	}
	public static class TableDTOCommand extends Command {

		@Override
		public WidgetDTO instantiate(EJObject ejObj, MarshallingSession ctx) {
			TableDTO tbdo = new TableDTO();
			super.initDefaultProps(ejObj, tbdo);
			if (ejObj.containsKey("view")) {
				EJValue viewChild = ejObj.get("view");
				Marshaller<Object> marshaller = ctx.getMarshallerInstance(ViewDTO.class.getName());
				Object dView = marshaller.demarshall(viewChild, ctx);
				tbdo.setView((ViewDTO) dView);
			}
			return tbdo;
		}
		
	}
	public static class TextAreaDTOCommand extends Command {

		@Override
		public WidgetDTO instantiate(EJObject ejObj, MarshallingSession ctx) {
			TextAreaDTO ta = new TextAreaDTO();
			super.initDefaultProps(ejObj, ta);
			if (ejObj.containsKey("view")) {
				ta.setSize(ejObj.get("view").isNumber().intValue());
			}
			return ta;
		}
		
	}
	public static class TextFieldDTOCommand extends Command {

		@Override
		public WidgetDTO instantiate(EJObject ejObj, MarshallingSession ctx) {
			TextFieldDTO tf = new TextFieldDTO();
			super.initDefaultProps(ejObj, tf);
			return tf;
		}
		
	}
	public static class FunctionWidgetDTOCommand extends Command {

		@Override
		public WidgetDTO instantiate(EJObject ejObj, MarshallingSession ctx) {
			Marshaller<Object> marshl = ctx.getMarshallerInstance(FunctionDTO.class.getName());
			EJValue ejValue = ejObj.get("function");
			FunctionWidgetDTO fw = new FunctionWidgetDTO((FunctionDTO) marshl.demarshall(ejValue, ctx));
			super.initDefaultProps(ejObj, fw);
			return fw;
		}
	}
}

